import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.Locale;
import java.util.Random; 



import pluginUtils.Circle;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.MobiusTransform;
import pluginUtils.CircleInversion;
import pluginUtils.PackCircle;
import pluginUtils.Point2D;
import pluginUtils.Pos3D;
import pluginUtils.Sphere;
import pluginUtils.SphereInversion;

// 

public class JuliaDrawingWithPovrayOutput extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=1000,Y=1000; // image size
	
	private PrintStream output;
	private double xShift=0; 
	private double zShift=0; 
	
	

	private Random generator=new Random(1214); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	private String[] palette={"Yellow","Red","Blue","Green","White","NavyBlue","Turquoise","Orange"};
	private Color[] palette1={Color.YELLOW,Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA,Color.ORANGE};
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	private void drawCircle(Point2D C,double r){
		double xCenter=C.getX(); 
		double yCenter=C.getY(); 
		
		primeIP.setColor(Color.BLUE); 
		//drawPoint(xCenter,-yCenter);
		primeIP.setColor(Color.BLACK);
		
		int intX=(int)((xCenter)*acoef+ccoef);
		int intY=(int)((yCenter)*vcoef+wcoef);
		int intRx=(int)(r*acoef);
		int intRy=(int)(r*vcoef);
		
		
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
	}
	
	private void drawPoint(double x,double y){
		int radi=1; 
		int intX=(int)(x*acoef+ccoef);
		int intY=(int)(y*vcoef+wcoef);
		primeIP.fillOval(intX-radi,intY-radi,2*radi,2*radi);
	}
	
	private void drawPoint(Point2D p){
		int intX=(int)(p.getX()*acoef+ccoef);
		int intY=(int)(p.getY()*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	
	private void drawLine(Point2D p,Point2D q){
		int XD=(int)(p.getX()*acoef+ccoef); 
		int YD=(int)(p.getY()*vcoef+wcoef); 
		int XF=(int)(q.getX()*acoef+ccoef); 
		int YF=(int)(q.getY()*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
		private double maxIter=5000.0;

		private double julia(int i,int j,Complexe c){
			
			//double x=(i-ccoef)/acoef;  
			//double y=(j-wcoef)/vcoef;
			double x=4.0/X*i-2; 
			double y=4.0/Y*j-2; 
			Complexe z=Complexe.createComplexeFromRI(x, y);
			int step=0; 
			while((step<maxIter)&&(z.getModule()<2)){
				step++; 
				double u=z.getReal()*z.getReal()-z.getIm()*z.getIm()+c.getReal(); 
				double v=2*z.getReal()*z.getIm()+c.getIm(); 
				z=Complexe.createComplexeFromRI(u, v);
			}
			return step/maxIter;
		}
	
		
		
			private double mandel(int i,int j){
			
				double x=(i-ccoef)/acoef;  
				double y=(j-wcoef)/vcoef; 
				Complexe c=Complexe.createComplexeFromRI(x, y);
				Complexe z=Complexe.ZERO; 
				int step=0; 
				while((z.getModule()<2)&&(step<maxIter)){
					step++; 
					double u=z.getReal()*z.getReal()-z.getIm()*z.getIm()+c.getReal(); 
					double v=2*z.getReal()*z.getIm()+c.getIm(); 
					z=Complexe.createComplexeFromRI(u, v);
				}
				return step/maxIter;
				
				
			}
			
			private int division=1; 
			
		
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
	
			try{
				output=new PrintStream("F:/Povray/outApollox4.txt");
				//output=new PrintStream("C:/users/decomite/pictures/povray/julia2.txt"); 
			}
			catch(Exception e){System.out.println("Probleme"); System.exit(0);}
		
		double limit=2; 
		double lmoins=-2;
		
		//setBounds(lmoins,limit,lmoins,limit);
		//setBounds(lmoins,limit,lmoins,limit);
		//setBounds(-0.7435725,-0.7435225,0.131733,0.131783);
		
		
		
		double xc=-0.71586; 
		double yc=0.28455; 
		double spread=2.2/376.0;
		
		setBounds(xc-spread,xc+spread,yc-spread,yc+spread); 
		//setBounds(-0.74780+fx,-0.74770+fx,0.09970-fy,0.09980-fy);
		setCoefs();
		
		
		float[] paletteBleue=new float[(int)maxIter+1]; 
		float[] paletteVerte=new float[(int)maxIter+1]; 
		float[] paletteRouge=new float[(int)maxIter+1]; 
		
		for(int i=0;i<maxIter;i++){
			paletteBleue[i]=generator.nextFloat(); 
			paletteVerte[i]=generator.nextFloat(); 
			paletteRouge[i]=generator.nextFloat(); 
		}
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		
		setProcessor("Verifying", primeIP);
		
		primeIP.setLineWidth(3);
		
		/*
		for(int i=0;i<division;i++){
			//if(i%10==0) 
			System.out.println(i); 
			for(int j=0;j<division;j++){ 
				// calculer l'ensemble de Julia du carre (i,j)
				// dont les coordonnees du coin superieur gauche en pixel sont (i*X/division,j*Y/division)
				// largeur : X/division pixels
				// coordonnees du point central ((i+1/2)*X/division,(j+1/2)*Y/division)=(U,V) en pixels
				// en reel : ((U-ccoef)/acoef,(V-wcoef)/vcoef)
				double U=(i+0.5)*X/(0.0+division);
				double V=(j+0.5)*Y/(0.0+division);
				U=(U-ccoef)/acoef;
				V=(V-wcoef)/vcoef; 
				Complexe c=Complexe.createComplexeFromRI(U, V); 
				
				for(int k=0;k<X/division;k++)
					for(int l=0;l<Y/division;l++){// La couleur d'un point
						double col=julia(k*division,l*division,c);
						primeIP.setColor(new Color(paletteRouge[(int)((maxIter)*col)],paletteVerte[(int)((maxIter)*col)],paletteBleue[(int)((maxIter)*col)])); 
						//primeIP.setColor(new Color((float)(4*col*(1-col)),(float)(0.2-0.2*col),(float)(1-col)));
						//primeIP.setColor(new Color((float)(i+j+0.0)/(2*division),(float)(i+2*j+0.0)/(3*division),(float)(2*i+j+0.0)/(3*division)));
						drawPoint(((i*X/division+k)-ccoef)/acoef,((j*Y/division+l)-wcoef)/vcoef ); 
						output.print((i*X/division+k)+","+(j*Y/division+l)+","+col+","+paletteRouge[(int)((maxIter)*col)]+","+paletteVerte[(int)((maxIter)*col)]+","+paletteBleue[(int)((maxIter)*col)]+",");
					}
				
			}
		
		}
		*/
	    double mincol=2; 
	    double maxcol=0; 
		for(int i=0;i<X;i++){
			for(int j=0;j<Y;j++){
				double col=mandel(i,j);
				if(col>maxcol) maxcol=col; 
				if(col<mincol) mincol=col; 
				primeIP.setColor(new Color((float)Math.cos(Math.PI/4*col),(float)Math.sin(Math.PI*col),(float)col));
				//primeIP.setColor(new Color((float)((col-1)*(col-1)),(float)(4*col*(1-col)),(float)Math.cos(Math.PI/2*col)));
				
				//primeIP.setColor(new Color((float)(1-col),(float)(4*col*(1-col)),(float)(0.5-0.5*col))); 
				
				drawPoint((i-ccoef)/acoef,(j-wcoef)/vcoef ); 
				output.print(i+","+j+","+col+",");
			}
			if(i%100==0) System.out.println(i); 
			
		}

		PrintStream output2; 	
		try{
			output2=new PrintStream("F:/Povray/outApolloauxi.txt");
			//output=new PrintStream("C:/users/decomite/pictures/povray/julia2.txt");
			output2.print(mincol+","+maxcol+","); 
			output2.close(); 
		}
		catch(Exception e){System.out.println("Probleme"); System.exit(0);}
		
		output.close(); 
		show();
	}	
}
